package team.archai.nexus.boot.tool;

import cn.hutool.core.bean.BeanUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.core.ResolvableType;

import java.io.*;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @description: bean工具类
 * @author: lishibin
 * @create: 2020-07-28 23:00
 **/
public class BeanUtils extends BeanUtil {

    private static final Log log = LogFactory.getLog(BeanUtils.class);

    /**
     * @program: BeanUtils
     * @description: 获取目标类
     * @author: lishibin
     * @create: 11:15 PM
     **/
    public static Class<?> getTargetClass(Object instance) {
        return (instance instanceof Class<?>) ? (Class<?>) instance : AopUtils.getTargetClass(instance);
    }

    /**
     * 从实例中获取目标对象的泛型定义类class
     *
     * @param instance 对象实例
     * @param index
     * @return
     */
    public static Class<?> getGenericClass(Object instance, int index) {
        Class<?> targetClass = getTargetClass(instance);
        return getGenericClass(targetClass, index);
    }

    public static Class<?> getGenericClass(Class<?> clazz, int index) {
        ResolvableType resolvableType = ResolvableType.forClass(clazz).getSuperType();
        ResolvableType[] types = resolvableType.getGenerics();
        if (Tool.isEmpty(types) || index >= types.length) {
            types = resolvableType.getSuperType().getGenerics();
        }
        if (Tool.notEmpty(types) && types.length > index) {
            return types[index].resolve();
        }
        log.debug("cant't find genericClass " + index + " in " + clazz.getName());
        return null;
    }


    /**
     * @program: BeanUtils
     * @description: 获取对应的lambda
     * @author: lishibin
     * @create: 11:26 PM
     **/
    public static SerializedLambda getSerializedLambda(Serializable fn) {
        SerializedLambda lambda = null;
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            lambda = (SerializedLambda) method.invoke(fn);
        } catch (Exception e) {
            log.error("getSerializedLambda error, class=" + fn.getClass().getSimpleName(), e);
        }
        return lambda;
    }

    /**
     * @program: BeanUtils
     * @description: 根据路径自动组装bean 嵌套
     * @author: lishibin
     * @create: 6:48 PM
     **/
    public static <T> void map2Bean(Map<?, ?> values, T t) {
        BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(t);
        wrapper.setAutoGrowNestedPaths(true);
        wrapper.setPropertyValues(values);
    }

    /**
     * @program: BeanUtils
     * @description: clone 对象
     * @author: lishibin
     * @create: 11:05 PM
     **/
    public static Object clone(final Object value) {
        // 字节数组输出流，暂存到内存中
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        // 序列化
        ObjectOutputStream oos;
        ObjectInputStream ois = null;
        Object obj = null;
        try {
            oos = new ObjectOutputStream(bos);
            oos.writeObject(value);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            obj = ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            log.error(e.getMessage());
        }
        // 反序列化
        return obj;
    }

    /**
     * @program: BeanUtils
     * @description: 获取类的实例
     * @author: lishibin
     * @create: 10:08 PM
     **/
    public static <T> T instance(Class<T> clazz) {
        T t = null;
        try {
            t = clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            log.error(e.getMessage());
        }
        return t;
    }

}
